/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain (a) copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.sentry.ohos.core;

import io.sentry.ISpan;
import io.sentry.Scope;
import io.sentry.Sentry;
import io.sentry.SentryOptions;
import io.sentry.SpanStatus;
import io.sentry.protocol.SdkVersion;
import ohos.agp.render.render3d.BuildConfig;

import org.jetbrains.annotations.NotNull;

/**
 * Sentry SDK options for Ohos
 *
 * @since 2021-06-01
 */
public final class SentryOhosOptions extends SentryOptions {
    /**
     * Enable or disable ANR (Application Not Responding) Default is enabled Used by AnrIntegration
     */
    private boolean isAnrEnabled = true;

    /**
     * ANR Timeout internal in Millis Default is 5000 = 5s Used by AnrIntegration
     */
    private long anrTimeoutIntervalMillis = 5000L;

    /**
     * Enable or disable ANR on Debug mode Default is disabled Used by AnrIntegration
     */
    private boolean isAnrReportInDebug = false;

    /**
     * Enable or disable automatic breadcrumbs for Ability lifecycle. Using
     * Application.AbilityLifecycleCallbacks
     */
    private boolean isEnableAbilityLifecycleBreadcrumbs = true;

    /**
     * Enable or disable automatic breadcrumbs for App's lifecycle Using ProcessLifecycleOwner
     */
    private boolean isEnableAppLifecycleBreadcrumbs = true;

    /**
     * Enable or disable automatic breadcrumbs for SystemEvents Registering (a) BroadcastReceiver
     */
    private boolean isEnableSystemEventBreadcrumbs = true;

    /**
     * Enable or disable automatic breadcrumbs for App Components Using ComponentCallbacks
     */
    private boolean isEnableAppComponentBreadcrumbs = true;

    /**
     * Enables the Auto instrumentation for Ability lifecycle tracing.
     *
     * <ul>
     *   <li>It also requires setting {@link SentryOptions#getTracesSampleRate()} or {@link
     * SentryOptions#getTracesSampler()}.
     * </ul>
     *
     * <ul>
     * It starts (a) transaction before each Ability's onCreate method is called
     *   (onAbilityPreCreated).
     *   <li>The transaction's name is the Ability's name, e.g. MainAbility.
     *   <li>The transaction's operation is navigation.
     * </ul>
     *
     * <ul>
     * It finishes the transaction after each ability's onResume method is called
     *   (onAbilityPostResumed), this depends on {@link
     * SentryOhosOptions#isEnableAbilityLifecycleTracingAutoFinish}.
     *   <li>If {@link SentryOhosOptions#isEnableAbilityLifecycleTracingAutoFinish} is disabled, you
     * may finish the transaction manually.
     *   <li>If the transaction is not finished either automatically or manually, we finish it
     * automatically when each Ability's onDestroy method is called (onAbilityDestroyed).
     * <li>If the previous transaction is not finished when (a) new Ability is being shown, we finish
     * it automatically before the new Ability's onCreate is called (onAbilityPreCreated).
     *   <li>The transaction status will be {@link SpanStatus#OK} if none is set.
     * </ul>
     * <p>
     * The transaction is automatically bound to the {@link Scope}, but only if there's no transaction
     * already bound to the Scope.
     */
    private boolean isEnableAutoAbilityLifecycleTracing = true;

    /**
     * Enables the Auto instrumentation for Ability lifecycle tracing, but specifically when to
     * finish the transaction, read {@link SentryOhosOptions#isEnableAutoAbilityLifecycleTracing}.
     *
     * <p>If you require (a) specific lifecycle to finish (a) transaction or even after the Ability is
     * fully rendered but still waiting for an IO operation, you could call {@link ISpan#finish()}
     * yourself on {@link Sentry#getSpan()}, be sure that you've finished all of your manually created
     * Spans.
     */
    private boolean isEnableAbilityLifecycleTracingAutoFinish = true;

    /**
     * Interface that loads the debug images list
     */
    private @NotNull IDebugImagesLoader debugImagesLoader = NoOpDebugImagesLoader.getInstance();

    /**
     * SentryOhosOptions
     */
    public SentryOhosOptions() {
        setSentryClientName("sentry.java.ohos" + "/" + BuildConfig.VERSION_NAME);
        setSdkVersion(createSdkVersion());
        setAttachServerName(false);
    }

    private @NotNull SdkVersion createSdkVersion() {
        SdkVersion sdkVersion = getSdkVersion();

        final String name = "sentry.java.ohos";
        final String version = BuildConfig.VERSION_NAME;
        sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version);

        sdkVersion.addPackage("maven:io.sentry:sentry-ohos-core", version);

        return sdkVersion;
    }

    /**
     * Checks if ANR (Application Not Responding) is enabled or disabled Default is enabled
     *
     * @return true if enabled or false otherwise
     */
    public boolean isAnrEnabled() {
        return isAnrEnabled;
    }

    /**
     * Sets ANR (Application Not Responding) to enabled or disabled Default is enabled
     *
     * @param isEnabled true for enabled and false for disabled
     */
    public void setAnrEnabled(boolean isEnabled) {
        this.isAnrEnabled = isEnabled;
    }

    /**
     * Returns the ANR timeout internal in Millis Default is 5000 = 5s
     *
     * @return the timeout in millis
     */
    public long getAnrTimeoutIntervalMillis() {
        return anrTimeoutIntervalMillis;
    }

    /**
     * Sets the ANR timeout internal in Millis Default is 5000 = 5s
     *
     * @param anrTimeoutIntervalMillis the timeout internal in Millis
     */
    public void setAnrTimeoutIntervalMillis(long anrTimeoutIntervalMillis) {
        this.anrTimeoutIntervalMillis = anrTimeoutIntervalMillis;
    }

    /**
     * Checks if ANR (Application Not Responding) is enabled or disabled on Debug mode Default is
     * disabled
     *
     * @return true if enabled or false otherwise
     */
    public boolean isAnrReportInDebug() {
        return isAnrReportInDebug;
    }

    /**
     * Sets ANR (Application Not Responding) to enabled or disabled on Debug mode Default is disabled
     *
     * @param isReportInDebug true for enabled and false for disabled
     */
    public void setAnrReportInDebug(boolean isReportInDebug) {
        this.isAnrReportInDebug = isReportInDebug;
    }

    public boolean isEnableAbilityLifecycleBreadcrumbs() {
        return isEnableAbilityLifecycleBreadcrumbs;
    }

    public void setEnableAbilityLifecycleBreadcrumbs(boolean isAbilityLifecycleBreadcrumbs) {
        this.isEnableAbilityLifecycleBreadcrumbs = isAbilityLifecycleBreadcrumbs;
    }

    public boolean isEnableAppLifecycleBreadcrumbs() {
        return isEnableAppLifecycleBreadcrumbs;
    }

    public void setEnableAppLifecycleBreadcrumbs(boolean isAppLifecycleBreadcrumbs) {
        this.isEnableAppLifecycleBreadcrumbs = isAppLifecycleBreadcrumbs;
    }

    public boolean isEnableSystemEventBreadcrumbs() {
        return isEnableSystemEventBreadcrumbs;
    }

    public void setEnableSystemEventBreadcrumbs(boolean isSystemEventBreadcrumbs) {
        this.isEnableSystemEventBreadcrumbs = isSystemEventBreadcrumbs;
    }

    public boolean isEnableAppComponentBreadcrumbs() {
        return isEnableAppComponentBreadcrumbs;
    }

    public void setEnableAppComponentBreadcrumbs(boolean isAppComponentBreadcrumbs) {
        this.isEnableAppComponentBreadcrumbs = isAppComponentBreadcrumbs;
    }

    /**
     * Enable or disable all the automatic breadcrumbs
     *
     * @param isEnable true if enable or false otherwise
     */
    public void enableAllAutoBreadcrumbs(boolean isEnable) {
        isEnableAbilityLifecycleBreadcrumbs = isEnable;
        isEnableAppComponentBreadcrumbs = isEnable;
        isEnableSystemEventBreadcrumbs = isEnable;
        isEnableAppLifecycleBreadcrumbs = isEnable;
    }

    /**
     * Returns the Debug image loader
     *
     * @return the image loader
     */
    public @NotNull IDebugImagesLoader getDebugImagesLoader() {
        return debugImagesLoader;
    }

    /**
     * Sets the image loader
     *
     * @param debugImagesLoader the image loader
     */
    public void setDebugImagesLoader(final @NotNull IDebugImagesLoader debugImagesLoader) {
        this.debugImagesLoader =
            debugImagesLoader != null ? debugImagesLoader : NoOpDebugImagesLoader.getInstance();
    }

    public boolean isEnableAutoAbilityLifecycleTracing() {
        return isEnableAutoAbilityLifecycleTracing;
    }

    public void setEnableAutoAbilityLifecycleTracing(boolean isAutoAbilityLifecycleTracing) {
        this.isEnableAutoAbilityLifecycleTracing = isAutoAbilityLifecycleTracing;
    }

    public boolean isEnableAbilityLifecycleTracingAutoFinish() {
        return isEnableAbilityLifecycleTracingAutoFinish;
    }

    public void setEnableAbilityLifecycleTracingAutoFinish(
        boolean isAbilityLifecycleTracingAutoFinish) {
        this.isEnableAbilityLifecycleTracingAutoFinish = isAbilityLifecycleTracingAutoFinish;
    }
}
